<?php

/* ========================================================================= */
/* This file is part of the HypnoPHP Framework Library                       */
/* Copyright (c) 2009-2010, Radu Buzea                                       */
/* ========================================================================= */

/**
* @author Radu Buzea
* @copyright Copyright (c) 2009-2010, Radu Buzea (www.hypnosis.ro)
* @license GNU Lesser General Public License (www.gnu.org/copyleft/lesser.html)
* @package HypnoPHP
* @category Core
* @version 1.0.3
*/
defined('HYPNOPHP_APPLICATION') or
die("Cannot use <i>" . basename(__FILE__) . "</i> outside HypnoPHP Application");

// ============================================================================
// Abstract class: HBaseController
// ============================================================================

abstract class HBaseController extends HBaseObject
{

	protected $__view_vars = array();
	protected $__model_class_name = '';

	# ###########################################################################

	/**
	* Run the controller.
	* This is the second executed action in the controller after
	* the '__initialize' method.
	*
	* @return void
	*/
	public function run()
	{
		if (!isset($this->view_object)) { $this->view_object = new HBaseView($this); }
		$this->getModelObject();
	}

	# ###########################################################################

	/**
	* Set the model class name
	*
	* @param string $model_class_name
	* @return bool
	*/
	public function setModelClassName($model_class_name = '')
	{
		$model_class_name = trim($model_class_name);
		if ($model_class_name == '' || !$this->__checkVarName($model_class_name)) {
			if ($model_class_name == '') { $model_class_name = "- the value is empty"; }
			else { $model_class_name = "<em>{$model_class_name}</em>"; }
			$this->addError("Invalid model class name {$model_class_name}", E_USER_ERROR);
			return false;
		}
		$this->__model_class_name = $model_class_name;
		return true;
	}

	# ###########################################################################

	/**
	* Search and load the assocaited model object
	*
	* @return HBaseModel or null if the model object doesn't exists
	*/
	public function getModelObject()
	{
		if (!isset($this->model_object) || !is_object($this->model_object)) {
			$model_object = null;
			$model_class_name = $this->__model_class_name;
			if ($model_class_name == '') {
				$model_class_name = str_replace('Controller_', 'Model_', get_class($this));
			}
			if (!class_exists($model_class_name, false)) {
				$model_class_object = HFactory::factory($model_class_name, false);
				if (is_object($model_class_object)) {
					$this->model_object = $model_object = $model_class_object;
					if (method_exists($model_object, 'run')) { $model_object->run(); }
				}
			}
		} else {
			$model_object = $this->model_object;
		}
		return $model_object;
	}

	# ###########################################################################

	/**
	* Controller method for URI redirects
	*
	* @param string $uri
	* @return void
	*/
	public function redirect($uri = '')
	{
		HResponse::redirect($uri);
	}

	# ###########################################################################

	/**
	* Set one or more variables to be used in the view object
	*
	* @param string or array $param1
	* @param mixed $param2 This is optional if $param1 is an array
	* @return bool
	*/
	public function setVar($param1, $param2 = null)
	{
		if (is_array($param1)) {
			if (is_array($param2)) { $vars = array_combine($param1, $param2); }
			else { $vars = $param1; }
			foreach ($vars as $param1_name => $param1_value) {
				if (!$this->setVar($param1_name, $param1_value)) { return false; }
			}
			return true;
		}
		if (isset($this->view_object) && is_object($this->view_object)) {
			return $this->view_object->setVar($param1, $param2);
		} else {
			if (!is_array($this->__view_vars)) { $this->__view_vars = array(); }
			$this->__view_vars[$param1] = $param2;
			return true;
		}
	}

	# ###########################################################################

	/**
	* Alias for the 'setVar' method
	*
	* @param string or array $param1
	* @param mixed $param2
	* @return bool
	*/
	public function set($param1, $param2 = null)
	{
		return $this->setVar($param1, $param2);
	}

	# ###########################################################################

	/**
	* Get a variable used in the view object
	*
	* @param string $param The variable name
	* @return mixed
	*/
	public function getVar($param = '')
	{
		if (isset($this->view_object) && is_object($this->view_object)) {
			return $this->view_object->getVar($param);
		} else {
			if (isset($this->__view_vars[$param])) { return $this->__view_vars[$param]; }
		}
		return null;
	}

	# ###########################################################################

	/**
	* Alias for 'getVar' method
	*
	* @param string $param The variable name
	* @return mixed
	*/
	public function get($param = '')
	{
		return $this->getVar($param);
	}

	# ###########################################################################

	/**
	* Search and execute an action method inside the controller
	* That is one of the most important methods in the framework
	*
	* @param string $action_name The action name
	* @param array $action_params A list of optonal action params
	* @param string $content_type The content type of the controller action output
	* @return string
	*/
	public function executeAction($action_name = '', $action_params = null, $content_type = 'text/html')
	{
		$exec_action_name = $action_name;
		if (!method_exists($this, $exec_action_name)) {
			$exec_action_name .= 'Action';
		}
		if (!method_exists($this, $exec_action_name)) {
			if (HApplication::debugMode()) {
				$controller = get_class($this);
				$this->addError("Action <em>{$action_name}</em> (or <em>{$exec_action_name}</em>) " .
					"does not exist in the <em>{$controller}</em> object", E_USER_ERROR);
				return false;
			} else {
				$debug_error_text = "Cannot find the controller for the requested address: <i>" .
					HApplication::requestURI() . "</i>";
				return HApplication::displayErrorPage(404, $debug_error_text);
			}
		}

		$this->disable_layout = false;
		$content_type = trim($content_type);
		if ($content_type == '') { $content_type = 'text/html'; }
		HResponse::set_content_type($content_type);

		// Authentication
		if ((isset($action_params['request_auth']) && $action_params['request_auth']) ||
			(isset($action_params['request_authentication']) && $action_params['request_authentication'])) {
			if (HAuthentication::check() == false) {
				$debug_error_text = "Could not verify that you are authorized to access the requested document. " .
					"Either you supplied the wrong credentials (bad username or password), or your browser does ".
					"not understand how to supply the required credentials.";
				return HApplication::displayErrorPage(401, $debug_error_text);
			}
		}

		$model_obj = $this->getModelObject();
		if (!is_null($model_obj) && is_object($model_obj)) {
			$model_action_name = $exec_action_name . 'Autorun';
			if (method_exists($model_obj, $model_action_name)) {
				$model_action_result = $model_obj->$model_action_name($action_params);
				if (!is_null($model_action_result)) {
					$this->setVar($model_action_name . '_result', $model_action_result);
				}
			}
		}

		$view_object = $this->view_object;
		if (is_array($this->__view_vars) && count($this->__view_vars) > 0) {
			foreach ($this->__view_vars as $name => $value) {
				$view_object->setVar($name, $value);
			}
		}
		$view_object->setRenderParams($action_params);
		$action_content = $this->$exec_action_name($action_params);
		if (!$this->disable_layout && HResponse::is_text_output()) {
			return $view_object->render($exec_action_name, $action_content);
		}
		return $action_content;
	}

	# ###########################################################################

}
